package com.sino.util;

import java.io.Reader;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Clob;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.Vector;

/**
 * Utility class to peform common String manipulation algorithms.
 */
public class StringUtils {
	public StringUtils() {
		try {
			jbInit();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	// constants used by escapeHTMLTags
	private static final char[] QUOTE_ENCODE = "&quot;".toCharArray();

	private static final char[] AMP_ENCODE = "&amp;".toCharArray();

	private static final char[] LT_ENCODE = "&lt;".toCharArray();

	private static final char[] GT_ENCODE = "&gt;".toCharArray();

	private static final char[] APOS_ENCODE = "&apos;".toCharArray();

	private static final char[] SPACE_ENCODE = "&nbsp;".toCharArray();

	/**
	 * Initialization lock for the whole class. Init's only happen once per
	 * class load so this shouldn't be a bottleneck.
	 */
	private static Object initLock = new Object();

	// // 将18位的身份证号码转变成15位
	public static String conversionZjhm(String zjhm) {
		if (zjhm == null) {
			return zjhm;
		} else if (zjhm.length() >= 18) {
			zjhm = zjhm.substring(0, 6) + zjhm.substring(8, 17);// 将18位的身份证号码转变成15位
		}
		return zjhm;
	}

	/**
	 * 通过对传入的输入值判断是否有非法字符
	 * 
	 * @param InputString
	 *            传入的字符串的值 对“<>"' ”进行Html转换防止sql错误，或者页面错误
	 * @return returnValse returnValse builder 李志东 build on 2006/03/15
	 */
	public static final String escapeForSQL(String InputString) {
		if (InputString == null) {
			return null;
		}
		char ch;
		int i = 0;
		int last = 0;
		char[] input = InputString.toCharArray();
		int len = input.length;
		StringBuffer out = new StringBuffer((int) (len * 1.3));
		for (; i < len; i++) {
			ch = input[i];
			if (ch > '>') {
				continue;
			} else if (ch == '<') {
				if (i > last) {
					out.append(input, last, i - last);
				}
				last = i + 1;
				out.append(LT_ENCODE);
			} else if (ch == '&') {
				if (i > last) {
					out.append(input, last, i - last);
				}
				last = i + 1;
				out.append(AMP_ENCODE);
			} else if (ch == '"' || ch == '\'') {
				if (i > last) {
					out.append(input, last, i - last);
				}
				last = i + 1;
				out.append(QUOTE_ENCODE);
			} else if (ch == ' ') {
				if (i > last) {
					out.append(input, last, i - last);
				}
				last = i + 1;
				out.append(SPACE_ENCODE);
			}

		}
		if (last == 0) {
			return InputString;
		}
		if (i > last) {
			out.append(input, last, i - last);
		}
		return out.toString();
	}

	/**
	 * Replaces all instances of oldString with newString in line.
	 * 
	 * @param line
	 *            the String to search to perform replacements on
	 * @param oldString
	 *            the String that should be replaced by newString
	 * @param newString
	 *            the String that will replace all instances of oldString
	 * 
	 * @return a String will all instances of oldString replaced by newString
	 */
	public static final String replace(String line, String oldString,
			String newString) {
		if (line == null) {
			return "";
		}
		int i = 0;
		if ((i = line.indexOf(oldString, i)) >= 0) {
			char[] line2 = line.toCharArray();
			char[] newString2 = newString.toCharArray();
			int oLength = oldString.length();
			StringBuffer buf = new StringBuffer(line2.length);
			buf.append(line2, 0, i).append(newString2);
			i += oLength;
			int j = i;
			while ((i = line.indexOf(oldString, i)) > 0) {
				buf.append(line2, j, i - j).append(newString2);
				i += oLength;
				j = i;
			}
			buf.append(line2, j, line2.length - j);
			return buf.toString();
		}
		return line;
	}

	public static final String toString(String[] StringArray) {
		String tempString = "";
		if (StringArray == null)
			return tempString;
		for (int i = 0; i < StringArray.length; i++) {
			if (!tempString.equals(""))
				tempString += ',';
			tempString += StringArray[i];
		}
		return tempString;
	}

	/**
	 * Replaces all instances of oldString with newString in line with the added
	 * feature that matches of newString in oldString ignore case.
	 * 
	 * @param line
	 *            the String to search to perform replacements on
	 * @param oldString
	 *            the String that should be replaced by newString
	 * @param newString
	 *            the String that will replace all instances of oldString
	 * 
	 * @return a String will all instances of oldString replaced by newString
	 */
	public static final String replaceIgnoreCase(String line, String oldString,
			String newString) {

		if (line == null) {
			return "";
		}
		String lcLine = line.toLowerCase();
		String lcOldString = oldString.toLowerCase();
		int i = 0;
		if ((i = lcLine.indexOf(lcOldString, i)) >= 0) {
			char[] line2 = line.toCharArray();
			char[] newString2 = newString.toCharArray();
			int oLength = oldString.length();
			StringBuffer buf = new StringBuffer(line2.length);
			buf.append(line2, 0, i).append(newString2);
			i += oLength;
			int j = i;
			while ((i = lcLine.indexOf(lcOldString, i)) > 0) {
				buf.append(line2, j, i - j).append(newString2);
				i += oLength;
				j = i;
			}
			buf.append(line2, j, line2.length - j);
			return buf.toString();
		}
		return line;
	}

	/**
	 * Replaces all instances of oldString with newString in line. The count
	 * Integer is updated with number of replaces.
	 * 
	 * @param line
	 *            the String to search to perform replacements on
	 * @param oldString
	 *            the String that should be replaced by newString
	 * @param newString
	 *            the String that will replace all instances of oldString
	 * 
	 * @return a String will all instances of oldString replaced by newString
	 */
	public static final String replace(String line, String oldString,
			String newString, int[] count) {
		if (line == null) {
			return "";
		}
		int i = 0;
		if ((i = line.indexOf(oldString, i)) >= 0) {
			int counter = 0;
			counter++;
			char[] line2 = line.toCharArray();
			char[] newString2 = newString.toCharArray();
			int oLength = oldString.length();
			StringBuffer buf = new StringBuffer(line2.length);
			buf.append(line2, 0, i).append(newString2);
			i += oLength;
			int j = i;
			while ((i = line.indexOf(oldString, i)) > 0) {
				counter++;
				buf.append(line2, j, i - j).append(newString2);
				i += oLength;
				j = i;
			}
			buf.append(line2, j, line2.length - j);
			count[0] = counter;
			return buf.toString();
		}
		return line;
	}

	/**
	 * This method takes a string which may contain HTML tags (ie, &lt;b&gt;,
	 * &lt;table&gt;, etc) and converts the '&lt'' and '&gt;' characters to
	 * their HTML escape sequences.
	 * 
	 * @param in
	 *            the text to be converted.
	 * @return the input string with the characters '&lt;' and '&gt;' replaced
	 *         with their HTML escape sequences.
	 */
	public static final String escapeHTMLTags(String in) {
		if (in == null) {
			return null;
		}
		char ch;
		int i = 0;
		int last = 0;
		char[] input = in.toCharArray();
		int len = input.length;
		StringBuffer out = new StringBuffer((int) (len * 1.3));
		for (; i < len; i++) {
			ch = input[i];
			if (ch > '>') {
				continue;
			} else if (ch == '<') {
				if (i > last) {
					out.append(input, last, i - last);
				}
				last = i + 1;
				out.append(LT_ENCODE);
			} else if (ch == '>') {
				if (i > last) {
					out.append(input, last, i - last);
				}
				last = i + 1;
				out.append(GT_ENCODE);
			}
		}
		if (last == 0) {
			return in;
		}
		if (i > last) {
			out.append(input, last, i - last);
		}
		return out.toString();
	}

	/**
	 * Used by the hash method.
	 */
	private static MessageDigest digest = null;

	/**
	 * Hashes a String using the Md5 algorithm and returns the result as a
	 * String of hexadecimal numbers. This method is synchronized to avoid
	 * excessive MessageDigest object creation. If calling this method becomes a
	 * bottleneck in your code, you may wish to maintain a pool of MessageDigest
	 * objects instead of using this method.
	 * <p>
	 * A hash is a one-way function -- that is, given an input, an output is
	 * easily computed. However, given the output, the input is almost
	 * impossible to compute. This is useful for passwords since we can store
	 * the hash and a hacker will then have a very hard time determining the
	 * original password.
	 * <p>
	 * In Jive, every time a user logs in, we simply take their plain text
	 * password, compute the hash, and compare the generated hash to the stored
	 * hash. Since it is almost impossible that two passwords will generate the
	 * same hash, we know if the user gave us the correct password or not. The
	 * only negative to this system is that password recovery is basically
	 * impossible. Therefore, a reset password method is used instead.
	 * 
	 * @param data
	 *            the String to compute the hash of.
	 * @return a hashed version of the passed-in String
	 */
	public static final String hash(String data) {
		if (digest == null) {
			try {
				digest = MessageDigest.getInstance("MD5");
			} catch (NoSuchAlgorithmException nsae) {
				System.err.println("Failed to load the MD5 MessageDigest. "
						+ "Jive will be unable to function normally.");
				nsae.printStackTrace();
			}
		}
		// Now, compute hash.
		digest.update(data.getBytes());
		return encodeHex(digest.digest());
	}

	/**
	 * Turns an array of bytes into a String representing each byte as an
	 * unsigned hex number.
	 * <p>
	 * Method by Santeri Paavolainen, Helsinki Finland 1996<br>
	 * (c) Santeri Paavolainen, Helsinki Finland 1996<br>
	 * Distributed under LGPL.
	 * 
	 * @param bytes
	 *            ：an array of bytes to convert to a he-string
	 * @return String ：generated hex string
	 */
	public static final String encodeHex(byte[] bytes) {
		StringBuffer buf = new StringBuffer(bytes.length * 2);
		int i;

		for (i = 0; i < bytes.length; i++) {
			if (((int) bytes[i] & 0xff) < 0x10) {
				buf.append("0");
			}
			buf.append(Long.toString((int) bytes[i] & 0xff, 16));
		}
		return buf.toString();
	}

	/**
	 * Turns a hex encoded string into a byte array. It is specifically meant to
	 * "reverse" the toHex(byte[]) method.
	 * 
	 * @param hex
	 *            a hex encoded String to transform into a byte array.
	 * @return a byte array representing the hex String[
	 */
	public static final byte[] decodeHex(String hex) {
		char[] chars = hex.toCharArray();
		byte[] bytes = new byte[chars.length / 2];
		int byteCount = 0;
		for (int i = 0; i < chars.length; i += 2) {
			byte newByte = 0x00;
			newByte |= hexCharToByte(chars[i]);
			newByte <<= 4;
			newByte |= hexCharToByte(chars[i + 1]);
			bytes[byteCount] = newByte;
			byteCount++;
		}
		return bytes;
	}

	/**
	 * Returns the the byte value of a hexadecmical char (0-f). It's assumed
	 * that the hexidecimal chars are lower case as appropriate.
	 * 
	 * @param ch
	 *            a hexedicmal character (0-f)
	 * @return the byte value of the character (0x00-0x0F)
	 */
	private static final byte hexCharToByte(char ch) {
		switch (ch) {
		case '0':
			return 0x00;
		case '1':
			return 0x01;
		case '2':
			return 0x02;
		case '3':
			return 0x03;
		case '4':
			return 0x04;
		case '5':
			return 0x05;
		case '6':
			return 0x06;
		case '7':
			return 0x07;
		case '8':
			return 0x08;
		case '9':
			return 0x09;
		case 'a':
			return 0x0A;
		case 'b':
			return 0x0B;
		case 'c':
			return 0x0C;
		case 'd':
			return 0x0D;
		case 'e':
			return 0x0E;
		case 'f':
			return 0x0F;
		}
		return 0x00;
	}

	// *********************************************************************
	// * Base64 - a simple base64 encoder and decoder.
	// *
	// * Copyright (c) 1999, Bob Withers - bwit@pobox.com
	// *
	// * This code may be freely used for any purpose, either personal
	// * or commercial, provided the authors copyright notice remains
	// * intact.
	// *********************************************************************

	/**
	 * Encodes a String as a base64 String.
	 * 
	 * @param data
	 *            a String to encode.
	 * @return a base64 encoded String.
	 */
	public static String encodeBase64(String data) {
		return encodeBase64(data.getBytes());
	}

	/**
	 * Encodes a byte array into a base64 String.
	 * 
	 * @param data
	 *            a byte array to encode.
	 * @return a base64 encode String.
	 */
	public static String encodeBase64(byte[] data) {
		int c;
		int len = data.length;
		StringBuffer ret = new StringBuffer(((len / 3) + 1) * 4);
		for (int i = 0; i < len; ++i) {
			c = (data[i] >> 2) & 0x3f;
			ret.append(cvt.charAt(c));
			c = (data[i] << 4) & 0x3f;
			if (++i < len)
				c |= (data[i] >> 4) & 0x0f;

			ret.append(cvt.charAt(c));
			if (i < len) {
				c = (data[i] << 2) & 0x3f;
				if (++i < len)
					c |= (data[i] >> 6) & 0x03;

				ret.append(cvt.charAt(c));
			} else {
				++i;
				ret.append((char) fillchar);
			}

			if (i < len) {
				c = data[i] & 0x3f;
				ret.append(cvt.charAt(c));
			} else {
				ret.append((char) fillchar);
			}
		}
		return ret.toString();
	}

	/**
	 * Decodes a base64 String.
	 * 
	 * @param data
	 *            ：a base64 encoded String to decode.
	 * @return String ：the decoded String.
	 */
	public static String decodeBase64(String data) {
		return decodeBase64(data.getBytes());
	}

	/**
	 * Decodes a base64 aray of bytes.
	 * 
	 * @param data
	 *            ：a base64 encode byte array to decode.
	 * @return ： the decoded String.
	 */
	public static String decodeBase64(byte[] data) {
		int c, c1;
		int len = data.length;
		StringBuffer ret = new StringBuffer((len * 3) / 4);
		for (int i = 0; i < len; ++i) {
			c = cvt.indexOf(data[i]);
			++i;
			c1 = cvt.indexOf(data[i]);
			c = ((c << 2) | ((c1 >> 4) & 0x3));
			ret.append((char) c);
			if (++i < len) {
				c = data[i];
				if (fillchar == c)
					break;

				c = cvt.indexOf((char) c);
				c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
				ret.append((char) c1);
			}

			if (++i < len) {
				c1 = data[i];
				if (fillchar == c1)
					break;

				c1 = cvt.indexOf((char) c1);
				c = ((c << 6) & 0xc0) | c1;
				ret.append((char) c);
			}
		}
		return ret.toString();
	}

	private static final int fillchar = '=';

	private static final String cvt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
			+ "abcdefghijklmnopqrstuvwxyz" + "0123456789+/";

	/**
	 * Converts a line of text into an array of lower case words. Words are
	 * delimited by the following characters: , .\r\n:/\+
	 * <p>
	 * In the future, this method should be changed to use a
	 * BreakIterator.wordInstance(). That class offers much more fexibility.
	 * 
	 * @param text
	 *            a String of text to convert into an array of words
	 * @return text broken up into an array of words.
	 */
	public static final String[] toLowerCaseWordArray(String text) {
		if (text == null || text.length() == 0) {
			return new String[0];
		}
		StringTokenizer tokens = new StringTokenizer(text, " ,\r\n.:/\\+");
		String[] words = new String[tokens.countTokens()];
		for (int i = 0; i < words.length; i++) {
			words[i] = tokens.nextToken().toLowerCase();
		}
		return words;
	}

	/**
	 * A list of some of the most common words. For searching and indexing, we
	 * often want to filter out these words since they just confuse searches.
	 * The list was not created scientifically so may be incomplete :)
	 */
	private static final String[] commonWords = new String[] { "a", "and",
			"as", "at", "be", "do", "i", "if", "in", "is", "it", "so", "the",
			"to" };

	private static Map commonWordsMap = null;

	/**
	 * Returns a new String array with some of the most common English words
	 * removed. The specific words removed are: a, and, as, at, be, do, i, if,
	 * in, is, it, so, the, to
	 */
	public static final String[] removeCommonWords(String[] words) {
		// See if common words map has been initialized. We don't statically
		// initialize it to save some memory. Even though this a small savings,
		// it adds up with hundreds of classes being loaded.
		if (commonWordsMap == null) {
			synchronized (initLock) {
				if (commonWordsMap == null) {
					commonWordsMap = new HashMap();
					for (int i = 0; i < commonWords.length; i++) {
						commonWordsMap.put(commonWords[i], commonWords[i]);
					}
				}
			}
		}
		// Now, add all words that aren't in the common map to results
		ArrayList results = new ArrayList(words.length);
		for (int i = 0; i < words.length; i++) {
			if (!commonWordsMap.containsKey(words[i])) {
				results.add(words[i]);
			}
		}
		return (String[]) results.toArray(new String[results.size()]);
	}

	/**
	 * Pseudo-random number generator object for use with randomString(). The
	 * Random class is not considered to be cryptographically secure, so only
	 * use these random Strings for low to medium security applications.
	 */
	private static Random randGen = null;

	/**
	 * Array of numbers and letters of mixed case. Numbers appear in the list
	 * twice so that there is a more equal chance that a number will be picked.
	 * We can use the array to get a random number or letter by picking a random
	 * array index.
	 */
	private static char[] numbersAndLetters = null;

	/**
	 * Returns a random String of numbers and letters (lower and upper case) of
	 * the specified length. The method uses the Random class that is built-in
	 * to Java which is suitable for low to medium grade security uses. This
	 * means that the output is only pseudo random, i.e., each number is
	 * mathematically generated so is not truly random.
	 * <p>
	 * 
	 * The specified length must be at least one. If not, the method will return
	 * null.
	 * 
	 * @param length
	 *            the desired length of the random String to return.
	 * @return a random String of numbers and letters of the specified length
	 */
	public static final String randomString(int length) {
		if (length < 1) {
			return null;
		}
		// Init of pseudo random number generator.
		if (randGen == null) {
			synchronized (initLock) {
				if (randGen == null) {
					randGen = new Random();
					// Also initialize the numbersAndLetters array
					numbersAndLetters = ("0123456789abcdefghijklmnopqrstuvwxyz"
							+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
							.toCharArray();
				}
			}
		}
		// Create a char buffer to put random letters and numbers in.
		char[] randBuffer = new char[length];
		for (int i = 0; i < randBuffer.length; i++) {
			randBuffer[i] = numbersAndLetters[randGen.nextInt(71)];
		}
		return new String(randBuffer);
	}

	/**
	 * Intelligently chops a String at a word boundary (whitespace) that occurs
	 * at the specified index in the argument or before. However, if there is a
	 * newline character before <code>length</code>, the String will be
	 * chopped there. If no newline or whitespace is found in
	 * <code>string</code> up to the index <code>length</code>, the String
	 * will chopped at <code>length</code>.
	 * <p>
	 * For example, chopAtWord("This is a nice String", 10) will return "This is
	 * a" which is the first word boundary less than or equal to 10 characters
	 * into the original String.
	 * 
	 * @param string
	 *            the String to chop.
	 * @param length
	 *            the index in <code>string</code> to start looking for a
	 *            whitespace boundary at.
	 * @return a substring of <code>string</code> whose length is less than or
	 *         equal to <code>length</code>, and that is chopped at
	 *         whitespace.
	 */
	public static final String chopAtWord(String string, int length) {
		if (string == null) {
			return string;
		}

		char[] charArray = string.toCharArray();
		int sLength = string.length();
		if (length < sLength) {
			sLength = length;
		}

		// First check if there is a newline character before length; if so,
		// chop word there.
		for (int i = 0; i < sLength - 1; i++) {
			// Windows
			if (charArray[i] == '\r' && charArray[i + 1] == '\n') {
				return string.substring(0, i + 1);
			}
			// Unix
			else if (charArray[i] == '\n') {
				return string.substring(0, i);
			}
		}
		// Also check boundary case of Unix newline
		if (charArray[sLength - 1] == '\n') {
			return string.substring(0, sLength - 1);
		}

		// Done checking for newline, now see if the total string is less than
		// the specified chop point.
		if (string.length() < length) {
			return string;
		}

		// No newline, so chop at the first whitespace.
		for (int i = length - 1; i > 0; i--) {
			if (charArray[i] == ' ') {
				return string.substring(0, i).trim();
			}
		}

		// Did not find word boundary so return original String chopped at
		// specified length.
		return string.substring(0, length);
	}

	/**
	 * Highlights words in a string. Words matching ignores case. The actual
	 * higlighting method is specified with the start and end higlight tags.
	 * Those might be beginning and ending HTML bold tags, or anything else.
	 * 
	 * @param string
	 *            the String to highlight words in.
	 * @param words
	 *            an array of words that should be highlighted in the string.
	 * @param startHighlight
	 *            the tag that should be inserted to start highlighting.
	 * @param endHighlight
	 *            the tag that should be inserted to end highlighting.
	 * @return a new String with the specified words highlighted.
	 */
	public static final String highlightWords(String string, String[] words,
			String startHighlight, String endHighlight) {
		if (string == null || words == null || startHighlight == null
				|| endHighlight == null) {
			return null;
		}

		// Iterate through each word.
		for (int x = 0; x < words.length; x++) {
			// we want to ignore case.
			String lcString = string.toLowerCase();
			// using a char [] is more efficient
			char[] string2 = string.toCharArray();
			String word = words[x].toLowerCase();

			// perform specialized replace logic
			int i = 0;
			if ((i = lcString.indexOf(word, i)) >= 0) {
				int oLength = word.length();
				StringBuffer buf = new StringBuffer(string2.length);

				// we only want to highlight distinct words and not parts of
				// larger words. The method used below mostly solves this. There
				// are a few cases where it doesn't, but it's close enough.
				boolean startSpace = false;
				char startChar = ' ';
				if (i - 1 > 0) {
					startChar = string2[i - 1];
					if (!Character.isLetter(startChar)) {
						startSpace = true;
					}
				}
				boolean endSpace = false;
				char endChar = ' ';
				if (i + oLength < string2.length) {
					endChar = string2[i + oLength];
					if (!Character.isLetter(endChar)) {
						endSpace = true;
					}
				}
				if ((startSpace && endSpace) || (i == 0 && endSpace)) {
					buf.append(string2, 0, i);
					if (startSpace && startChar == ' ') {
						buf.append(startChar);
					}
					buf.append(startHighlight);
					buf.append(string2, i, oLength).append(endHighlight);
					if (endSpace && endChar == ' ') {
						buf.append(endChar);
					}
				} else {
					buf.append(string2, 0, i);
					buf.append(string2, i, oLength);
				}

				i += oLength;
				int j = i;
				while ((i = lcString.indexOf(word, i)) > 0) {
					startSpace = false;
					startChar = string2[i - 1];
					if (!Character.isLetter(startChar)) {
						startSpace = true;
					}

					endSpace = false;
					if (i + oLength < string2.length) {
						endChar = string2[i + oLength];
						if (!Character.isLetter(endChar)) {
							endSpace = true;
						}
					}
					if ((startSpace && endSpace)
							|| i + oLength == string2.length) {
						buf.append(string2, j, i - j);
						if (startSpace && startChar == ' ') {
							buf.append(startChar);
						}
						buf.append(startHighlight);
						buf.append(string2, i, oLength).append(endHighlight);
						if (endSpace && endChar == ' ') {
							buf.append(endChar);
						}
					} else {
						buf.append(string2, j, i - j);
						buf.append(string2, i, oLength);
					}
					i += oLength;
					j = i;
				}
				buf.append(string2, j, string2.length - j);
				string = buf.toString();
			}
		}
		return string;
	}

	/**
	 * Escapes all necessary characters in the String so that it can be used in
	 * an XML doc.
	 * 
	 * @param in
	 *            ：string the string to escape.
	 * @return String ：the string with appropriate characters escaped.
	 */
	public static final String escapeForXML(String in) {
		if (in == null) {
			return null;
		}
		char ch;
		int i = 0;
		int last = 0;
		char[] input = in.toCharArray();
		int len = input.length;
		StringBuffer out = new StringBuffer((int) (len * 1.3));
		for (; i < len; i++) {
			ch = input[i];
			if (ch > '>') {
				continue;
			} else if (ch == '<') {
				if (i > last) {
					out.append(input, last, i - last);
				}
				last = i + 1;
				out.append(LT_ENCODE);
			} else if (ch == '&') {
				if (i > last) {
					out.append(input, last, i - last);
				}
				last = i + 1;
				out.append(AMP_ENCODE);
			} else if (ch == '"') {
				if (i > last) {
					out.append(input, last, i - last);
				}
				last = i + 1;
				out.append(QUOTE_ENCODE);
			}
		}
		if (last == 0) {
			return in;
		}
		if (i > last) {
			out.append(input, last, i - last);
		}
		return out.toString();
	}

	/**
	 * Unescapes the String by converting XML escape sequences back into normal
	 * characters.
	 * 
	 * @param string
	 *            the string to unescape.
	 * @return the string with appropriate characters unescaped.
	 */
	public static final String unescapeFromXML(String string) {
		string = replace(string, "&lt;", "<");
		string = replace(string, "&gt;", ">");
		string = replace(string, "&quot;", "\"");
		return replace(string, "&amp;", "&");
	}

	private static final char[] zeroArray = "0000000000000000".toCharArray();

	/**
	 * Pads the supplied String with 0's to the specified length and returns the
	 * result as a new String. For example, if the initial String is "9999" and
	 * the desired length is 8, the result would be "00009999". This type of
	 * padding is useful for creating numerical values that need to be stored
	 * and sorted as chracter data. Note: the current implementation of this
	 * method allows for a maximum <tt>length</tt> of 16.
	 * 
	 * @param string
	 *            the original String to pad.
	 * @param length
	 *            the desired length of the new padded String.
	 * @return a new String padded with the required number of 0's.
	 */
	public static final String zeroPadString(String string, int length) {
		StringBuffer buf = new StringBuffer(length);
		buf.append(zeroArray, 0, length - string.length()).append(string);
		return buf.toString();
	}

	/**
	 * Formats a Date as a fifteen character long String made up of the Date's
	 * padded millisecond value.
	 * 
	 * @return a Date encoded as a String.
	 */
	public static final String dateToMillis(Date date) {
		return zeroPadString(Long.toString(date.getTime()), 15);
	}

	// 页面到数据库调用char2Gb2312
	public static String char2Gb2312(String strInString) {
		String str = "";
		try {
			if (strInString == null || strInString.equals(""))
				return strInString;
			str = new String(strInString.getBytes("ISO8859-1"), "gb2312");
			return str;
		} catch (Exception e) {
			return "char2Gb2312转换错误！";
		}
	}

	// 数据库到页面调用char2ISO
	public static String char2ISO(String strInString) {
		String str = "";
		try {
			if (strInString == null || strInString.equals(""))
				return strInString;
			str = new String(strInString.getBytes("gb2312"), "ISO8859-1");
			return str;
		} catch (Exception e) {
			return "char2Gb2312转换错误！";
		}
	}
	//UTF8 转GBK
	public static String charUTF8TOGBK(String strInString){
		String str = "";
		try {
			if (strInString == null || strInString.equals(""))return strInString;
			str = new String(strInString.getBytes("utf-8"), "GBK");return str;
		} catch (Exception e) {
			return "utf-8 Gb2312转换错误！";
		}
	}

	/**
	 * 此处插入方法说明。 创建日期：(2002-7-24 22:29:20)
	 * 
	 * @param str
	 *            ：java.lang.String
	 * @return java.lang.String
	 */
	public static final String nullToKong(String str) {
		if (str == null || str.equals("null"))
			return "";
		else
			return str;
	}

	/**
	 * 此处插入方法说明。 创建日期：(2002-8-3 下午 09:47:08)
	 * 
	 * @return java.lang.String
	 */
	public static String getCurrDate(int formatType) {
		java.util.Date currDate = new java.util.Date();
		String dateString = null;
		java.text.SimpleDateFormat formatter;

		if (formatType == 1) {
			formatter = new java.text.SimpleDateFormat("yyyy-MM-dd");
		} else {
			formatter = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		}
		dateString = formatter.format(currDate);
		return dateString;
	}

	public static String getCurrDate(String formatStr) {
		java.util.Date currDate = new java.util.Date();
		String dateString = null;
		java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat(
				formatStr);
		dateString = formatter.format(currDate);
		return dateString;
	}

	public static String getNewCurrDate(String format) {
		Calendar now = Calendar.getInstance();
		int year = now.get(Calendar.YEAR);
		int month = now.get(Calendar.MONTH);
		int day = now.get(Calendar.DAY_OF_MONTH);
		int hour = now.get(Calendar.HOUR_OF_DAY);
		int minute = now.get(Calendar.MINUTE);
		int second = now.get(Calendar.SECOND);
		String currdate;
		if (format.equals("1")) {
			currdate = year + "-" + (month + 1) + "-" + day;
		} else {
			currdate = year + "-" + (month + 1) + "-" + day + "" + hour + ":"
					+ minute + ":" + second;
			;
		}
		return currdate;
	}

	public static Date getStirngToDate(String StrDate, String format) {
		java.text.DateFormat f1 = new java.text.SimpleDateFormat(
				"yy-MM-dd-HH-mm-ss");
		java.text.DateFormat f = new java.text.SimpleDateFormat("yy-MM-dd");
		java.util.Date date1 = null;
		try {
			if (format.equals("1")) {
				date1 = f.parse(StrDate);
			} else {
				date1 = f.parse(StrDate);
			}
		} catch (Exception e) {

			e.printStackTrace();
		}
		return date1;
	}

	static public boolean isEqual(String a, String b) {
		if (a == null) {
			return (b == null);
		} else {
			return a.equals(b);
		}
	}

	/**
	 * 此处插入方法说明。 创建日期：(2002-9-17 0:38:33)
	 * 
	 * @param args
	 *            java.lang.String[]
	 */
	public static void main(String[] args) {
		// Log.debug(encodeBase64("test"));
		// Log.debug(decodeBase64(encodeBase64("test")));\
		StringUtils sul = new StringUtils();
		System.out.println(sul.getStirngToDate(sul.getNewCurrDate("1"), "1"));
	}

	/**
	 * 此处插入方法说明。 创建日期：(2002-9-3 21:13:00)
	 * 
	 * @return java.lang.String
	 * @param strs
	 *            ：java.lang.String
	 */
	public static String[] stringToArray(String strs) {
		if (strs != null) {
			strs = strs + ",";
			int count = 0;
			int pos = 0;
			int pos1 = 0;
			pos1 = strs.indexOf(",", pos);
			do {
				String str = strs.substring(pos, pos1);
				pos = pos1 + 1;
				count = count + 1;
				pos1 = strs.indexOf(",", pos);
			} while (pos1 != -1);
			String[] array = new String[count];
			pos = 0;
			pos1 = 0;
			count = 0;
			pos1 = strs.indexOf(",", pos);
			do {
				String str = strs.substring(pos, pos1);
				array[count] = str;
				pos = pos1 + 1;
				count = count + 1;
				pos1 = strs.indexOf(",", pos);
			} while (pos1 != -1);
			return array;
		}
		return null;
	}

	public static String[] stringToArray(String strs, String specialStr) {
		if (strs != null) {
			strs = strs + specialStr;
			int count = 0;
			int pos = 0;
			int pos1 = 0;
			pos1 = strs.indexOf(specialStr, pos);
			do {
				String str = strs.substring(pos, pos1);
				pos = pos1 + 1;
				count = count + 1;
				pos1 = strs.indexOf(specialStr, pos);
			} while (pos1 != -1);
			String[] array = new String[count];
			pos = 0;
			pos1 = 0;
			count = 0;
			pos1 = strs.indexOf(specialStr, pos);
			do {
				String str = strs.substring(pos, pos1);
				array[count] = str;
				pos = pos1 + 1;
				count = count + 1;
				pos1 = strs.indexOf(specialStr, pos);
			} while (pos1 != -1);
			return array;
		}
		return null;
	}

	/**
	 * 功能：还原Html的格式输出。 作者：Alwin 日期：2002-11-24
	 */
	public static final String htmlEncode(String string) {
		string = StringUtils.replace(string, "<", "&lt;");
		string = StringUtils.replace(string, ">", "&gt;");
		string = StringUtils.replace(string, "\n", "<br>");
		string = StringUtils.replace(string, " ", "&nbsp;");
		return StringUtils.replace(string, "'", "&#39");
	}

	public static final String getHtmlEncodeRow(String source, int len) {
		int strLen = source.length();
		String tempStr = source;
		String endStr = "";

		if (tempStr.lastIndexOf("</P>") == -1) {

			return source;

		} else {

			int size = 0;

			while (tempStr.lastIndexOf("</P>") != -1) {
				int start = tempStr.indexOf("<P>");
				int end = tempStr.indexOf("</P>");

				size = end - 0;
				if (start > 0) {
					endStr += tempStr.substring(0, start);
				}
				if (size > len) {

					endStr += tempStr.substring(start, start + len);
					endStr += "</P>";
					tempStr = "<P>" + tempStr.substring(start + len);

				} else {
					endStr += tempStr.substring(start, end + 4);
					tempStr = tempStr.substring(end + 4);
				}

			}
			return endStr;
		}

	}

	public static String[] vectorToStrings(Vector tempV) {
		if (tempV != null || tempV.size() != 0) {
			String[] tempStrs = new String[tempV.size()];
			for (int i = 0; i < tempV.size(); i++) {
				tempStrs[i] = (String) tempV.elementAt(i);
			}
			return tempStrs;
		} else {
			return null;
		}
	}

	// 转换成GB2312并同时用"''"替换"'"
	public static String strToGB2312AndRepacle(String newStr) {
		String str = StringUtils.char2Gb2312(newStr);
		return StringUtils.replace(str, "'", "''");
	}

	/**
	 * 根据考生的身份证获得考生的出生日期
	 * 
	 * @param zjlb
	 *            :证件类别
	 * @param zjhm
	 *            :证件号码
	 * @return String :返回考生的出生日期
	 */
	public static String getCsrqByZjhm(String zjlb, String zjhm) {
		String csrq = null;// 出生日起
		if (zjlb.equals("01") && zjhm != null) {
			if (zjhm.length() == 15) {
				csrq = "19" + zjhm.substring(6, 8) + "-"
						+ zjhm.substring(8, 10) + "-" + zjhm.substring(10, 12);
			}
			if (zjhm.length() == 18) {
				csrq = zjhm.substring(6, 10) + "-" + zjhm.substring(10, 12)
						+ "-" + zjhm.substring(12, 14);
			}
		}
		return csrq;
	}

	/**
	 * 
	 * @param len
	 *            截取字符串长度
	 * @param source
	 *            源字符串
	 * @return string 截取后的字符串
	 */
	public static String getZnOfomit(int len, String source) {
		if (source == null)
			return null;

		int start, stop, byteLen;
		int alen = source.getBytes().length; // 获得源字符字节长度
		// len += len ;
		if (len > 0) {
			if (alen <= len)
				return source; // 小于等于指定长度原样返回
			start = stop = byteLen = 0; // TODO effizienter
			// stop = (len > alen ? alen : len);

			while (byteLen <= len) {
				if (source.substring(stop, stop + 1).getBytes().length == 1) {
					byteLen += 1;
				} else {
					byteLen += 2;
				}
				stop++;
			}
			StringBuffer sb = new StringBuffer(source
					.substring(start, stop - 1));
			if (alen > len)
				sb.append("");
			return sb.toString();
		}
		start = (len < -alen ? 0 : alen + len);
		stop = alen;
		StringBuffer sb = new StringBuffer(source
				.substring(start / 2, stop / 2));
		if (-alen <= len)
			sb.insert(0, "");
		return sb.toString();
	}

	/**
	 * 根据考生的身份证获得考生的性别
	 * 
	 * @param zjlb
	 *            :证件类别
	 * @param zjhm
	 *            :证件号码
	 * @param type
	 *            :1性别用“男”、“女”，type=0性别用“1”，“0”
	 * @return String :返回考生的性别
	 */
	public static String getXbByZjhm(String zjlb, String zjhm, String type) {
		String xb = null;// 出生日起
		int temxb;
		if (zjlb.equals("01") && zjhm != null) {
			if (zjhm.length() == 15) {
				xb = zjhm.substring(14, 15);
				temxb = Integer.parseInt(xb);
				if ((temxb % 2) == 0) {
					if (type.equals("1")) {
						xb = "女";
					} else {
						xb = "0";
					}
				}
				if ((temxb % 2) != 0) {
					if (type.equals("1")) {
						xb = "男";
					} else {
						xb = "1";
					}
				}
			}
			if (zjhm.length() == 18) {
				xb = zjhm.substring(16, 17);
				temxb = Integer.parseInt(xb);
				if ((temxb % 2) == 0) {
					if (type.equals("1")) {
						xb = "女";
					} else {
						xb = "0";
					}
				}
				if ((temxb % 2) != 0) {
					if (type.equals("1")) {
						xb = "男";
					} else {
						xb = "1";
					}
				}
			}
		}
		return StringUtils.char2ISO(xb);
	}

	// 获得随机字符串
	public static String GetRandomChar(int intLength) {
		String retStr = "";
		String strTable = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz";
		int len = strTable.length();
		boolean bDone = true;
		do {
			retStr = "";
			int count = 0;
			for (int i = 0; i < intLength; i++) {
				double dblR = Math.random() * len;
				int intR = (int) Math.floor(dblR);
				char c = strTable.charAt(intR);
				if (('0' <= c) && (c <= '9')) {
					count++;
				}
				retStr += strTable.charAt(intR);
			}
			if (count >= 2) {
				bDone = false;
			}
		} while (bDone);

		return retStr;

	}
	

	public final static String clob2String(Clob clob) {
		if (clob == null) {
			return "";
		}

		StringBuffer sb = new StringBuffer(65535);// 64K
		Reader clobStream = null;
		try {
			clobStream = clob.getCharacterStream();
			char[] b = new char[60000];// 每次获取60K
			int i = 0;
			while ((i = clobStream.read(b)) != -1) {
				sb.append(b, 0, i);
			}
		} catch (Exception ex) {
			sb = null;
		} finally {
			try {
				if (clobStream != null)
					clobStream.close();
			} catch (Exception e) {
			}
		}
		if (sb == null)
			return "";
		else
			return sb.toString();
	}

	/**
	 * 功能：获取RowSet中的字段值，如果是null则返回空
	 */
	public static String getRowSetString(javax.sql.RowSet rs, String field_name)
			throws Exception {
		return nullToKong(rs.getString(field_name));
	}

	public static String getFormatCode(String format, int i) {
		return (format + i).substring(Integer.toString(i).length(),
				(format + i).length());
	}

	private void jbInit() throws Exception {

	}

	public static String doubleToString(Double dParam) {
		if (null != dParam) {
			return dParam.toString();
		} else {
			return null;
		}
	}
	
}
